/**
 * Collaborative Story Development Web Application (CSDApp) Copyright Anton
 * Strack 2014
 *
 * This file is part of Collaborative Story Development Application (CSDApp).
 *
 * CSDApp is free software: you can redistribute it and/or modify it under the
 * terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or any later version.
 *
 * CSDApp is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * CSDApp. If not, see <http://www.gnu.org/licenses/>.
 *
 */
package csdwa;

import java.sql.Connection;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.http.HttpSession;

/**
 * This class handles the end user's interaction with the site primarily with
 * logging in and out but also with searching functionality.
 *
 * @author Anton Strack
 */
public class SiteController extends ResourceController implements CsdwaController {

    private final String VIEW_INDEX = "/index.jsp";
    private final String VIEW_VIEW = "/site/view.jsp"; // default search results view
    protected String target;

    // private Connection conn;
    public SiteController(Connection conn) {
        super(conn);
        target = VIEW_INDEX;
    }

//    public SiteController(Connection conn) {
//        this.conn = conn;
//        target = VIEW_INDEX;
//    }
    /**
     * This method handles get requests. It accepts the primaryResouce and
     * primaryAction as variables to allow routing from the handleGetRequest
     * method.
     *
     * @param primaryResource the primary resource that will handle the request
     * @param primaryAction the primary action on the resource.
     * @param request the request object
     * @return
     */
    @Override
    public CsdwaRequest handleGetRequest(CsdwaRequest request) {
        this.target = VIEW_INDEX;// default

        String resource = request.getPrimaryResourceTypeName();
        if (resource == null || resource.isEmpty()) {
            resource = "site";
            request.setPrimaryResourceTypeName(resource);
        }
        String action = request.getPrimaryActionTypeName();
        if (action == null || action.isEmpty()) {
            action = "view";
            request.setPrimaryActionTypeName(action);
        }


        if ("site".equalsIgnoreCase(request.getPrimaryResourceTypeName())) {
            String query = request.getParameter("query");
            if ("logout".equalsIgnoreCase(request.getPrimaryActionTypeName())) {
                HttpSession session = request.getRequest().getSession();
                Site site = new Site();
                this.getResourceRequestDelegator().getUserHistoryManager().recordUserPostHistory(request.getCurrentUser(), InfoAggregator.getInstance().getActionTypeId("logout"), site);
                request.removeAttribute("loggedIn");
                session.removeAttribute("user");
                session.invalidate(); // will move this handling to accessControl eventually
            }
            if ("search".equalsIgnoreCase(request.getPrimaryActionTypeName()) && query != null && query.isEmpty() == false) {
                this.target = VIEW_VIEW;

                String searchType = request.getParameter("type");
                if (searchType != null && searchType.isEmpty() == false) {
                    request.setMessage("Search types are not implemented yet.");
                    request.setMessageType("info");
                    Logger.getLogger(TaskController.class.getName()).log(Level.WARNING, "Search types are not implemented yet.");
                } else {
                    request = this.handleDefaultSearch(request, query);
                }
            }
        }
        request.setView(this.target);
        return request;
    }

    @Override
    public CsdwaRequest handlePostRequest(CsdwaRequest request) {
        String form = request.getFormId();
        this.target = VIEW_VIEW;
        if (form.isEmpty() == false) {
            if (form.equalsIgnoreCase("login-site")) {
                request.removeFormId();
                request = handleLogin(request);
            } else if ("search-site".equalsIgnoreCase(form)) {
                String query = request.getParameter("searchQuery");
                request = this.handleDefaultSearch(request, query);
                request.setView(this.target);
            }
        }
        return request;
    }

//    public CsdwaRequest handleRequest(CsdwaRequest request) {
//        if ("POST".equalsIgnoreCase(request.getMethod()) && request.getParameter("formSubmit") != null) {
//            return this.handlePostRequest(request);
//        } else {
//            String resource = request.getPrimaryResourceTypeName();
//            if (resource == null || resource.isEmpty()) {
//                resource = "site";
//                request.setPrimaryResourceTypeName(resource);
//            }
//            String action = request.getPrimaryActionTypeName();
//            if (action == null || action.isEmpty()) {
//                action = "view";
//                request.setPrimaryActionTypeName(action);
//            }
//            return this.handleGetRequest(request);
//        }
//    }
    /**
     * Handle the login form logic.
     *
     * @param request the request object containing the username and password
     * from the login form.
     * @return the processed request object.
     */
    private CsdwaRequest handleLogin(CsdwaRequest request) {
        AccessControl ac = new AccessControl(conn);
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        User user = ac.authenticateLogin(username, password, request.getRequest());
        request.setPrimaryActionTypeName(request.getRefererAction());
        request.setPrimaryResourceTypeName(request.getRefererResource());
        request.setMethod("GET");
        if (user.getRoleId() != InfoAggregator.getInstance().getRoleTypeId("guest")) {
            if ("logout".equalsIgnoreCase(request.getRefererAction()))// temp hack to fix successful logins from being logged out if user logged out right before.
            {
                request.setPrimaryActionTypeName("view");
                request.setPrimaryResourceTypeName("site");
            }
            request.setMessage("Login successful.");
            request.setMessageType("success");
            Site site = new Site();
            this.getResourceRequestDelegator().getUserHistoryManager().recordUserPostHistory(request.getCurrentUser(), InfoAggregator.getInstance().getActionTypeId("login"), site);
        } else {
            request.setMessage("Login failed.");
            request.setMessageType("error");
        }
        ResourceRequestDelegator rrd = new ResourceRequestDelegator(conn);
        request = rrd.processRequest(request);
        return request;
    }

    /**
     * The default search includes selecting all of the four domain types that
     * have a query match in their name or description field.
     *
     * @param request the request object that will be returned with the search
     * results;
     * @param query the query to search in the name and description fields of
     * the four domain types. If the query is longer than 30 characters long,
     * then search will not be preformed. Instead return an error message.
     * @return the result of the search or an error message if the search query
     * was too long.
     */
    private CsdwaRequest handleDefaultSearch(CsdwaRequest request, String query) {
        request.setAttribute("searchQuery", query);// return the search query so it can be displayed to the user.
        int matchCount = 0;
        if (query.length() > 40) {
            request.setMessage("The search query is too long.");
            request.setMessageType("error");
        } else if (query.length() < 4) {
            request.setMessage("The search query is too short. It must be greater than 3 characters long.");
            request.setMessageType("error");
        } else if (query.matches("^\\d+")) {
            request.setMessage("The search query can't begin with numbers.");
            request.setMessageType("error");
        } else {
            DaoFactory daoFactory = new DaoFactory(conn);
            InfoAggregator infoAggregator = InfoAggregator.getInstance();
            CsdwaDao<Plot> plotDao = daoFactory.getDao(infoAggregator.getResourceTypeId("plot"));
            CsdwaDao<Character> characterDao = daoFactory.getDao(infoAggregator.getResourceTypeId("character"));
            CsdwaDao<Dialog> dialogDao = daoFactory.getDao(infoAggregator.getResourceTypeId("dialog"));
            CsdwaDao<Location> locationDao = daoFactory.getDao(infoAggregator.getResourceTypeId("location"));
            if (plotDao != null) {
                plotDao.setUseRelatedMarkers(true);
                matchCount += plotDao.selectBeanSearchQuery(query);
                request.setAttribute("plotResults", plotDao.getBeans());
            }
            if (locationDao != null) {
                locationDao.setUseRelatedMarkers(true);
                matchCount += locationDao.selectBeanSearchQuery(query);
                request.setAttribute("locationResults", locationDao.getBeans());
            }
            if (characterDao != null) {
                characterDao.setUseRelatedMarkers(true);
                matchCount += characterDao.selectBeanSearchQuery(query);
                request.setAttribute("characterResults", characterDao.getBeans());
            }
            if (dialogDao != null) {
                dialogDao.setUseRelatedMarkers(true);
                matchCount += dialogDao.selectBeanSearchQuery(query);
                request.setAttribute("dialogResults", dialogDao.getBeans());
            }
            if (matchCount == 0) {
                request.setMessage("No matches were found for the provided search query.");
                request.setMessageType("info");
            }
            // set the site name to query so it can be displayed in the user history
            Site site = new Site(query);
            this.getResourceRequestDelegator().getUserHistoryManager().recordUserPostHistory(request.getCurrentUser(), InfoAggregator.getInstance().getActionTypeId("search"), site);
        }
        request.setAttribute("matchCount", matchCount);
        return request;
    }
}
